﻿using System;
using FITClub.Episode1.Components;
using FITClub.Episode1.Controller;
using Microsoft.Xna.Framework;

namespace FITClub.Episode1.Controller.AI
{
    /// <summary>
    /// Airtificial inteligence player.
    /// </summary>
    public class AIPlayer : APlayer
    {
        private Waypoints waypoints;
        private PlayableCharacter character;
        private WPNode start;
        private WPNode end;

        protected PseudoRandom random;
        protected float MinDistX = 0.02687f;
        protected float PunchDist = 0.5f;
        protected int punchCycles = 0;
        protected float MaxCurrDist = 0;

        public AIPlayer(string Name, Waypoints waypoints, PlayableCharacter character)
            : base(Name)
        {
            //float distPerFrame = MathHelper.TwoPi * character.CharPhysx.Motor.R * character.CharPhysx.MotorSpeed / 60f;
            this.waypoints = waypoints;
            this.character = character;
            this.character.Killed += new Action<PlayableCharacter>(character_Killed);
            this.character.GotPunch += new Action<PlayableCharacter, PlayableCharacter>(character_PlayerGotPunch);
            this.random = new PseudoRandom();
        }

        private void character_PlayerGotPunch(PlayableCharacter arg1, PlayableCharacter arg2)
        {
        }

        private void character_Killed(PlayableCharacter obj)
        {
            this.start = null;
            this.end = null;
            this.punchCycles = 0;
        }

        public override void Update()
        {
            base.Update();
            Vector2 chPos = character.Position;
            if (this.character.Visible)
            {
                if (this.start == null)
                {
                    this.ResetState(chPos);
                }
                else
                {
                    this.DecideAndMove(chPos);
                }
                try
                {
                    TryToPunch(chPos);
                }
                catch
                {
                }
            }
        }

        private void TryToPunch(Vector2 chPos)
        {
            bool punch = false;
            foreach (var item in character.game.characters.Values)
            {
                if (item.FadeOut > 0 && item.Name != this.character.Name)
                {
                    Vector2 enemyPos = item.Position;
                    float dist = Vector2.Distance(chPos, item.Position);
                    if (dist <= this.PunchDist)
                    {
                        if (enemyPos.X < chPos.X)   /// pozicia je zrejme prevratena oproti worldu
                        {
                            this.SetState(false, (int)VirtualGamepadButtons.Right);
                            this.SetState(true, (int)VirtualGamepadButtons.Left);
                        }
                        else
                        {
                            this.SetState(true, (int)VirtualGamepadButtons.Right);
                            this.SetState(false, (int)VirtualGamepadButtons.Left);
                        }
                        punch = true;
#if DEBUG
                        System.Diagnostics.Debug.WriteLine("char={0}   enemy={1};   left={2} right={3}", chPos.X, enemyPos.X, this.ControllerStateActual.Left, this.ControllerStateActual.Right);
#endif
                        break;
                    }
                }
            }
            if (punch)
            {
                punchCycles++;

                this.SetState((punchCycles % 20 > 10), (int)VirtualGamepadButtons.Attack);
                if (punchCycles >= 2)
                {
                    this.SetState(false, (int)VirtualGamepadButtons.Left);
                    this.SetState(false, (int)VirtualGamepadButtons.Right);
                }
#if DEBUG
                System.Diagnostics.Debug.WriteLine("punchCycles={0} attack={1}", punchCycles, this.ControllerStateActual[(int)VirtualGamepadButtons.Attack]);
#endif
            }
            else
            {
                if (punchCycles != 0)
                {
                    this.SetState(false, (int)VirtualGamepadButtons.Attack);
                    punchCycles = 0;
                    this.ResetState(chPos);
                }
            }
        }

        private void DecideAndMove(Vector2 chPos)
        {
            float distX = Math.Abs(chPos.X - end.Position.X);
            float dist = Vector2.Distance(chPos, end.Position);
            if (dist > MaxCurrDist)
            {
                /// we are lost, reset position in graph
#if DEBUG
                System.Diagnostics.Debug.WriteLine("we are lost, MaxCurrDist={0}    dist={1}", MaxCurrDist, dist);
#endif
                ResetState(chPos);
                return;
            }

            if (distX > this.MinDistX)
            {
                this.ControllerStateActual = this.ControllerStatePrevious;
            }
            else
            {
                WPNode next;
                if (end.Behaviour == NodeBahaviour.TurnBack)
                {
                    next = start; /// otocit
                }
                else
                {
                    int rand = random.GetInt32(end.SiblingsCount);
                    next = end.Siblings[rand];

                    float deltaY = next.Position.Y - end.Position.Y;
#if DEBUG
                    System.Diagnostics.Debug.WriteLine(" next={0}, delta={1}", next, deltaY);
#endif
                    if ((end.Behaviour & NodeBahaviour.Jump) == NodeBahaviour.Jump)
                    {
                        /// jump left or right
                        ///this.SetState(true, (end.Behaviour == NodeBahaviour.JumpRight) ? (int)VirtualGamepadButtons.Right : (int)VirtualGamepadButtons.Left);
                        this.SetState(true, 0);
                    }
                }
                start = end;
                end = next;
                SetMaxCurrDist();
                if (start.Behaviour == NodeBahaviour.PassLeft || start.Behaviour == NodeBahaviour.PassRight)
                {
                    this.SetState(true, (int)((start.Behaviour == NodeBahaviour.PassLeft) ? VirtualGamepadButtons.Left : VirtualGamepadButtons.Right));
                }
                else
                {
                    this.DecideDirection();
                }
            }
        }

        protected void DecideDirection()
        {
            this.DecideDirection(start.Position, end.Position);
        }

        protected void DecideDirection(Vector2 startPoint, Vector2 endPoint)
        {
            this.SetState(true, (startPoint.X > endPoint.X) ? (int)VirtualGamepadButtons.Left : (int)VirtualGamepadButtons.Right);
        }

        private void ResetState(Vector2 chPos)
        {
            this.waypoints.Find(chPos, out start, out end);
            if (start == null)
            {
                return;
            }
            if (Vector2.Distance(chPos, start.Position) < Vector2.Distance(chPos, end.Position))
            {
                WPNode h = start;
                start = end;
                end = h;
            }
            SetMaxCurrDist();
            this.DecideDirection(chPos, end.Position);
        }

        private void SetMaxCurrDist()
        {
            MaxCurrDist = Vector2.Distance(start.Position, end.Position) + 0.03f;
#if DEBUG
            System.Diagnostics.Debug.WriteLine("maxCurDist={2}    start={0}, end={1}", start.Position, end.Position, MaxCurrDist);
#endif
        }

        public override void Dispose()
        {
        }
    }
}